package net.oschina.simpleplus.erpc.consumer;

import java.util.List;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.google.protobuf.Descriptors.FieldDescriptor;
import com.google.protobuf.GeneratedMessageV3;

import io.netty.channel.ChannelHandlerContext;
import net.oschina.simpleplus.erpc.api.ERpcContainer;
import net.oschina.simpleplus.erpc.api.FastMethodInvoker;
import net.oschina.simpleplus.erpc.core.ERpcRequestEntity;
import net.oschina.simpleplus.erpc.core.ERpcResultEntity;
import net.oschina.simpleplus.erpc.support.ProtobufCache;

public class ConsumerTask implements Runnable{
	private static final Logger logger = LoggerFactory.getLogger(ConsumerTask.class);
	private ChannelHandlerContext ctx;
	private ERpcRequestEntity msg;
	
	private ERpcContainer container;
	
	public ConsumerTask(ChannelHandlerContext ctx, ERpcRequestEntity msg, ERpcContainer container) {
		super();
		this.ctx = ctx;
		this.msg = msg;
		this.container = container;
	}
	
	@Override
	public void run() {
		ERpcResultEntity eRpcResultEntity = new ERpcResultEntity();
		eRpcResultEntity.setMsgId(msg.getMsgId());
		try {
			
			FastMethodInvoker fastMethodInvoker = container.find(msg.getServiceName(), msg.getMethodName());
			Object result = fastMethodInvoker.invoke(getSortedParams(ProtobufCache.merge(fastMethodInvoker.getErpc().req(), msg.getArgs())));
			logger.info("after invoke result:{}", result);
			if(result instanceof GeneratedMessageV3){
				eRpcResultEntity.setBody(((GeneratedMessageV3)result).toByteArray());
			}else if(result instanceof Void){
				eRpcResultEntity.setMsg("invoke success");
			}else{
				eRpcResultEntity.setCode(4000);
				eRpcResultEntity.setMsg("invoke fail----");
			}
		} catch (Exception e) {
			e.printStackTrace();
			eRpcResultEntity.setCode(4000);
			eRpcResultEntity.setMsg(e.getMessage());
		}
		ctx.channel().writeAndFlush(eRpcResultEntity);		
	}
	private Object[] getSortedParams(GeneratedMessageV3 proto) {
		List<FieldDescriptor> fields = proto.getDescriptorForType().getFields();
        int size = fields.size();
        Object[] params = new Object[size];
        for (int i = 0; i < size; i++) {
            FieldDescriptor fieldDescriptor = fields.get(i);
            params[i] = proto.getField(fieldDescriptor);
        }
        return params;
    }
}
